package com.thb.pay.manage.web.sys;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.thb.pay.api.sys.vo.req.SysUserReq;
import com.thb.pay.api.sys.vo.resp.SysResourceVo;
import com.thb.pay.api.sys.vo.resp.SysUserRoleVo;
import com.thb.pay.api.sys.vo.resp.SysUserVo;
import com.thb.pay.core.annotation.LoginRequired;
import com.thb.pay.core.annotation.OperationLog;
import com.thb.pay.core.cache.EhcacheUtils;
import com.thb.pay.core.enums.ExceptionEnum;
import com.thb.pay.core.exception.RRException;
import com.thb.pay.core.utils.*;
import com.thb.pay.manage.service.FeginCommService;
import com.thb.pay.vo.req.UpdatePwdReq;
import com.xiaoleilu.hutool.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * @Description 主页面controller
 * @Author lucky
 * @data 2019/7/28 22:14
 */
@Slf4j
@RestController
@RequestMapping("/api/sys/main")
public class MainController {

    @Autowired
    private FeginCommService feginCommService;

    private static List<SysResourceVo> compare(List<SysResourceVo> list) {
        Set<SysResourceVo> set = new TreeSet<>(new Comparator<SysResourceVo>() {
            @Override
            public int compare(SysResourceVo o1, SysResourceVo o2) {
                return o1.getId().compareTo(o2.getId());
            }
        });
        set.addAll(list);
        return Lists.newArrayList(set);
    }

    @PostMapping(value = "/logout")
    @OperationLog(value = "退出")
    public R logout() {
        SysUserVo sysUserVo = (SysUserVo) ContextHolder.getUserInfo();
        EhcacheUtils.getInstance().remove(String.format(Constant.ACCESS_TOKEN, sysUserVo.getAccessToken()));
        return R.ok();
    }

    /**
     * 查询当前用户信息
     *
     * @return
     */
    @GetMapping("/current")
    public R current() {
        Long userId = ContextHolder.getUserId();
        SysUserVo sysUserVo = feginCommService.sysUserServiceApi.getByUserId(userId);
        return R.okData(sysUserVo);
    }

    /**
     * 刷新token
     *
     * @return
     */
    @LoginRequired
    @GetMapping(value = "/refresh")
    public R refreshToken() {
        Long userId = ContextHolder.getUserId();
        SysUserVo sysUserVo = feginCommService.sysUserServiceApi.getByUserId(userId);
        String accessToken = IdWorker.get32UUID();
        String refreshToken = IdWorker.get32UUID();
        sysUserVo.setAccessToken(accessToken);
        sysUserVo.setRefreshToken(refreshToken);
        EhcacheUtils.getInstance().set(String.format(Constant.ACCESS_TOKEN, accessToken), sysUserVo, Constant.EXPIRE_ACCESS_TOKEN_TIME);
        EhcacheUtils.getInstance().set(String.format(Constant.REFRESH_TOKEN, refreshToken), sysUserVo, Constant.EXPIRE_REFRESH_TOKEN_TIME);

        JSONObject data = new JSONObject();
        data.put("token", accessToken);
        data.put("refreshToken", refreshToken);
        return R.okData(data);
    }

    /**
     * 修改当前用户登录密码
     *
     * @return
     */
    @PostMapping("/updatePwd")
    @OperationLog(value = "修改密码")
    public R updatePassword(@RequestBody UpdatePwdReq updatePwdReq) {
        Long userId = ContextHolder.getUserId();
        SysUserVo sysUser = feginCommService.sysUserServiceApi.getByUserId(userId);
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(updatePwdReq.getOldPassWord(), sysUser.getPassword())) { // 验证旧密码是否正确
            throw RRException.build(ExceptionEnum.PASSWORD_ERROR);
        }
        /**
         * 判断新密码格式
         */
        if (!StrUtil.checkPassword(updatePwdReq.getPassWord())) {
            throw RRException.build(ExceptionEnum.PASSWORD_FORMAT_ERROR);
        }
        feginCommService.sysUserServiceApi.updateUser(SysUserReq.builder()
                .id(userId)
                .password(encoder.encode(updatePwdReq.getPassWord()))
                .lastPasswordResetTime(new Date())
                .build());
        return R.ok();
    }

    /**
     * 查询用户菜单
     * @return
     */
    @GetMapping("/menu")
    public R menu() {
        Long userId = ContextHolder.getUserId();
        SysUserVo sysUserVo = feginCommService.sysUserServiceApi.getByUserId(userId);
        List<SysResourceVo> resourceVoList = Lists.newArrayList();
        if (Constant.PUB_YES.compareTo(sysUserVo.getIsSuperAdmin()) == 0) {
            resourceVoList = feginCommService.sysResourceServiceApi.findListBySystemType(Constant.SYSTEM_MANAGE);
        } else {
            List<SysResourceVo> userResourceVoList = feginCommService.sysResourceServiceApi.findListByUserId(userId);

            List<SysUserRoleVo> userRoleVoList = feginCommService.sysUserServiceApi.findUserRolesByUserId(userId);
            List<Long> roleIds = Lists.newArrayList();
            userRoleVoList.forEach(sysUserRoleVo -> {
                roleIds.add(sysUserRoleVo.getRoleId());
            });
            List<SysResourceVo> roleResourceVoList = feginCommService.sysResourceServiceApi.findListByRoleIds(roleIds);
            resourceVoList.addAll(userResourceVoList);
            resourceVoList.addAll(roleResourceVoList);
        }
        resourceVoList = compare(resourceVoList);

        List<MenuBuilder.Node> nodeList = Lists.newLinkedList();
        if (CollUtil.isNotEmpty(resourceVoList)) {
            resourceVoList.forEach(sysResourceVo -> {
                MenuBuilder.Node node = new MenuBuilder.Node();
                node.setResourceId(sysResourceVo.getId());
                node.setName(sysResourceVo.getName());
                node.setTitle(sysResourceVo.getTitle());
                if (StringUtils.isNotBlank(sysResourceVo.getJump())) node.setJump(sysResourceVo.getJump());
                if (StringUtils.isNotBlank(sysResourceVo.getIcon())) node.setIcon(sysResourceVo.getIcon());
                node.setParentId(sysResourceVo.getParentId());
                nodeList.add(node);
            });
        }
        return R.okData(nodeList);
    }
}
